﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.Device.Location;
using System.Windows.Threading;
using Microsoft.Phone.Maps.Services;
using System.Globalization;
using System.Diagnostics;
using Microsoft.Phone.Maps.Controls;
using System.Windows.Media.Imaging;
using System.ComponentModel;
using System.Windows.Media;

namespace INdTFramework.Controls
{
    public partial class RouteOnMap : UserControl
    {
        bool requestedRoute;
        RouteQuery routeQuery;
        List<GeoCoordinate> coordinates;

        public static DependencyProperty BeginningCoordinatesProperty = DependencyProperty.Register("BeginningCoordinates", typeof(GeoCoordinate), typeof(RouteOnMap), new PropertyMetadata(BeginningCoordinatesChanged));
        public static DependencyProperty DestinationCoordinatesProperty = DependencyProperty.Register("DestinationCoordinates", typeof(GeoCoordinate), typeof(RouteOnMap), new PropertyMetadata(DestinationCoordinatesChanged));
        public static DependencyProperty BeginningPinProperty = DependencyProperty.Register("BeginningPin", typeof(ImageSource), typeof(RouteOnMap), new PropertyMetadata(null));
        public static DependencyProperty DestinationPinProperty = DependencyProperty.Register("DestinationPin", typeof(ImageSource), typeof(RouteOnMap), new PropertyMetadata(null));

        public ImageSource BeginningPin
        {
            get
            {
                return GetValue(BeginningPinProperty) as ImageSource;
            }

            set
            {
                SetValue(BeginningPinProperty, value);
            }
        }

        public ImageSource DestinationPin
        {
            get
            {
                return GetValue(DestinationPinProperty) as ImageSource;
            }

            set
            {
                SetValue(DestinationPinProperty, value);
            }
        }

        [TypeConverter(typeof(GeoCoordinateConverter))]
        public GeoCoordinate BeginningCoordinates
        {
            get
            {
                return GetValue(BeginningCoordinatesProperty) as GeoCoordinate;
            }

            set
            {
                SetValue(BeginningCoordinatesProperty, value);
                CheckDestinationCoordinates();
            }
        }

        [TypeConverter(typeof(GeoCoordinateConverter))]
        public GeoCoordinate DestinationCoordinates
        {
            get
            {
                return GetValue(DestinationCoordinatesProperty) as GeoCoordinate;
            }

            set
            {
                SetValue(DestinationCoordinatesProperty, value);
                CheckBeginningCoordinates();
            }
        }

        public RouteOnMap()
        {
            InitializeComponent();

            coordinates = new List<GeoCoordinate>();
            requestedRoute = false;
        }

        static void BeginningCoordinatesChanged(DependencyObject dependecyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            var control = dependecyObject as RouteOnMap;

            if (control != null)
            {
                control.BeginningCoordinates = dependencyPropertyChangedEventArgs.NewValue as GeoCoordinate;
            }
        }

        static void DestinationCoordinatesChanged(DependencyObject dependecyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            var control = dependecyObject as RouteOnMap;

            if (control != null)
            {
                control.DestinationCoordinates = dependencyPropertyChangedEventArgs.NewValue as GeoCoordinate;
            }
        }

        void CheckBeginningCoordinates()
        {
            if (BeginningCoordinates != null && !requestedRoute)
            {
                GetRoute();
            }
        }

        void CheckDestinationCoordinates()
        {
            if (DestinationCoordinates != null && !requestedRoute)
            {
                GetRoute();
            }
        }

        void GetRoute()
        {
            requestedRoute = true;
            Map.Visibility = Visibility.Collapsed;
            ProgressIndicator.Visibility = Visibility.Visible;

            coordinates.Add(BeginningCoordinates);
            coordinates.Add(DestinationCoordinates);

            routeQuery = new RouteQuery();
            routeQuery.TravelMode = TravelMode.Driving;
            routeQuery.RouteOptimization = RouteOptimization.MinimizeDistance;
            routeQuery.Waypoints = coordinates;
            routeQuery.QueryCompleted += QueryCompleted;
            routeQuery.QueryAsync();
        }

        void QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
        {
            if (e.Error == null)
            {
                ShowRoute(e.Result);
            }
            else
            {
                Debug.WriteLine("Erro: " + e.Error.Message);
            }
        }

        void ShowRoute(Route route)
        {
            var mapRoute = new MapRoute(route);
            Map.AddRoute(mapRoute);
            Map.Center = GetCenter(coordinates[0], coordinates[1]);

            var overlayBeginning = new MapOverlay();
            overlayBeginning.Content = BeginningPin != null ? new Image { Source = BeginningPin } : null;
            overlayBeginning.GeoCoordinate = coordinates[0];
            overlayBeginning.PositionOrigin = new Point(0.5, 0.5);

            var overlayDestination = new MapOverlay();
            overlayDestination.Content = DestinationPin != null ? new Image { Source = DestinationPin } : null;
            overlayDestination.GeoCoordinate = coordinates[1];
            overlayDestination.PositionOrigin = new Point(0.5, 0.5);

            var layer = new MapLayer();
            layer.Add(overlayBeginning);
            layer.Add(overlayDestination);

            Map.Layers.Add(layer);
            ProgressIndicator.Visibility = Visibility.Collapsed;
            Map.Visibility = Visibility.Visible;
        }

        GeoCoordinate GetCenter(GeoCoordinate beginning, GeoCoordinate destination)
        {
            var newLatitude = (beginning.Latitude + destination.Latitude) / 2;
            var newLongitude = (beginning.Longitude + destination.Longitude) / 2;

            return new GeoCoordinate(newLatitude, newLongitude);
        }
    }
}
